﻿namespace HZY.Framework.MinimalApi.SourceGenerator;

/// <summary>
/// 最小 api 生成器
/// </summary>
[Generator]
public class MinimalApiGenerator : ISourceGenerator

{
    private readonly string stringPr = @"
 /*
 * *******************************************************
 *
 * 作者：hzy
 *
 * 开源地址：https://gitee.com/hzy6
 *
 * *******************************************************
 */
        ";

    public void Initialize(GeneratorInitializationContext context)
    {
        // 注册一个语法接收器，它会在编译时收集所有的类和它们的公共方法
        context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
    }

    public void Execute(GeneratorExecutionContext context)
    {
        //Debugger.Launch();

        // 获取语法接收器，并检查它是否收集到了任何类
        if (context.SyntaxReceiver is SyntaxReceiver receiver && receiver.Classes.Any())
        {
            GeneratorMinimalApi(context, receiver.Classes);
        }
    }

    private class SyntaxReceiver : ISyntaxReceiver
    {
        public List<ClassDeclarationSyntax> Classes { get; } = new List<ClassDeclarationSyntax>();

        public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
        {
            if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax)
            {
                Classes.Add(classDeclarationSyntax);
            }
        }
    }

    private void GeneratorMinimalApi(GeneratorExecutionContext context, List<ClassDeclarationSyntax> classes)
    {
        var methodBodyBuilder = new StringBuilder();

        var usingList = new StringBuilder();

        #region 为每个类生成一个最小的 API

        foreach (var @class in classes)
        {
            // 检查类是否有 MinimalApiAttribute 特性标记
            var attribute = @class.AttributeLists
                .SelectMany(x => x.Attributes)
                .FirstOrDefault(x => x.Name.ToString() == "DynamicMinimalApiAttribute" || x.Name.ToString() == "DynamicMinimalApi");
            if (attribute == null) continue;
            // 获取特性中的属性值

            var className = @class.Identifier.Text;
            var namespaceName = @class.Parent is NamespaceDeclarationSyntax namespaceDeclaration
                ? namespaceDeclaration.Name.ToString() : @class.Parent is FileScopedNamespaceDeclarationSyntax namespaceDeclarationSyntax ? namespaceDeclarationSyntax.Name.ToString() : null;

            if (!string.IsNullOrWhiteSpace(namespaceName))
            {
                usingList.AppendLine("using " + namespaceName + ";");
            }

            methodBodyBuilder.AppendLine($"     var _{className} = app.Services.GetService<{className}>();");

            // 为每个公共方法生成一个 API 方法
            foreach (var method in @class.DescendantNodes().OfType<MethodDeclarationSyntax>())
            {
                if (method.Modifiers.Any(SyntaxKind.PublicKeyword))
                {
                    var methodName = method.Identifier.Text;

                    // 提取出函数的参数
                    var parameters = method.ParameterList.Parameters.Select(x => x.Identifier.Text);

                    // 检查函数是否为 void
                    if (method.ReturnType.ToString() == "void")
                    {
                        // context.ReportDiagnostic(Diagnostic.Create(
                        //     new DiagnosticDescriptor(
                        //         id: "DW001",
                        //         title: "Minimal API",
                        //         messageFormat: "Method '{0}' must return void",
                        //         category: "Minimal API",
                        //         DiagnosticSeverity.Error,
                        //         isEnabledByDefault: true),
                        //     method.GetLocation(),
                        //     methodName));
                        // continue;

                        methodBodyBuilder.AppendLine($$"""
                                    app.MapGet("/api/{{className}}/{{methodName}}", ({{string.Join(",", method.ParameterList.Parameters)}}) =>
                                    {
                                        _{{className}}.{{methodName}}({{string.Join(",", parameters)}}));
                                    });
                            """);

                        continue;
                    }

                    var isAsync = method.ReturnType.ToString().StartsWith("Task");

                    methodBodyBuilder.AppendLine($$"""
                                    app.MapGet("/api/{{className}}/{{methodName}}",{{(isAsync ? "async" : "")}} ({{string.Join(",", method.ParameterList.Parameters)}}) =>
                                    {
                                        return Results.Json({{(isAsync ? "await" : "")}} _{{className}}.{{methodName}}({{string.Join(",", parameters)}}));
                                    });
                            """);

                }
            }
        }

        #endregion

        string apiClass = $$"""
                    {{stringPr}}

                    // <auto-generated/>

                    using HZY.Framework.MinimalApi.SourceGenerator;
                    using Microsoft.AspNetCore.Mvc;
                    {{usingList}}

                    namespace Microsoft.Extensions.DependencyInjection;
                    
                     public static class DynamicMinimalApiExtensions
                    {

                        public static DynamicMinimalApiOptions DynamicMinimalApiOptions;
                        
                         /// <summary>
                         /// 添加 动态 Web Api
                         /// </summary>
                         public static void AddDynamicMinimalApi(this WebApplicationBuilder builder,Action<DynamicMinimalApiOptions>? options)
                        {
                            DynamicMinimalApiOptions = new DynamicMinimalApiOptions();
                            options?.Invoke(DynamicMinimalApiOptions);
                        }

                         /// <summary>
                         /// 使用 动态 Web Api
                         /// </summary>
                         public static void UseDynamicMinimalApi(this WebApplication app)
                        {
                            {{methodBodyBuilder}}
                        }
                    }

                    """;

        context.AddSource($"DynamicMinimalApiExtensions", SourceText.From(apiClass, Encoding.UTF8));



        string apiClass1 = $$"""
                    {{stringPr}}
                    using System.Text;

                    // <auto-generated/>

                    namespace HZY.Framework.MinimalApi.SourceGenerator;

                     [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
                     public class DynamicMinimalApiAttribute : Attribute
                    {
                         /// <summary>
                         /// 使用 动态 Web Api
                         /// </summary>
                         public DynamicMinimalApiAttribute()
                        {

                        }
                    }

                    """;

        context.AddSource($"DynamicMinimalApiAttribute", SourceText.From(apiClass1, Encoding.UTF8));

        var apiClass2 = $$"""
            {{stringPr}}
            // <auto-generated/>
            namespace HZY.Framework.MinimalApi.SourceGenerator;

            /// <summary>
            /// api 参数项
            /// </summary>
            public class DynamicMinimalApiOptions
            {
                /// <summary>
                /// 控制器 和 action 路由用小写
                /// </summary>
                public bool IsLower { get; set; } = true;

                /// <summary>
                /// HttpMethod 映射关系
                /// </summary>
                public Dictionary<string, DynamicMinimalApiHttpMethodEnum> HttpMethodRule { get; } = new()
                {
                    ["post"] = DynamicMinimalApiHttpMethodEnum.POST,
                    ["add"] = DynamicMinimalApiHttpMethodEnum.POST,
                    ["create"] = DynamicMinimalApiHttpMethodEnum.POST,
                    ["insert"] = DynamicMinimalApiHttpMethodEnum.POST,
                    ["submit"] = DynamicMinimalApiHttpMethodEnum.POST,
                    ["get"] = DynamicMinimalApiHttpMethodEnum.GET,
                    ["find"] = DynamicMinimalApiHttpMethodEnum.GET,
                    ["fetch"] = DynamicMinimalApiHttpMethodEnum.GET,
                    ["query"] = DynamicMinimalApiHttpMethodEnum.GET,
                    ["put"] = DynamicMinimalApiHttpMethodEnum.PUT,
                    ["update"] = DynamicMinimalApiHttpMethodEnum.PUT,
                    ["delete"] = DynamicMinimalApiHttpMethodEnum.DELETE,
                    ["remove"] = DynamicMinimalApiHttpMethodEnum.DELETE,
                    ["clear"] = DynamicMinimalApiHttpMethodEnum.DELETE,
                    ["patch"] = DynamicMinimalApiHttpMethodEnum.PATCH,
                    ["options"] = DynamicMinimalApiHttpMethodEnum.OPTIONS,

                    //["post"] = "POST",
                    //["add"] = "POST",
                    //["create"] = "POST",
                    //["insert"] = "POST",
                    //["submit"] = "POST",
                    //["get"] = "GET",
                    //["find"] = "GET",
                    //["fetch"] = "GET",
                    //["query"] = "GET",
                    //["put"] = "PUT",
                    //["update"] = "PUT",
                    //["delete"] = "DELETE",
                    //["remove"] = "DELETE",
                    //["clear"] = "DELETE",
                    //["patch"] = "PATCH"

                };


            }



            /// <summary>
            /// 请求类型
            /// </summary>
            public enum DynamicMinimalApiHttpMethodEnum
            {
                /// <summary>
                /// 
                /// </summary>
                POST,
                /// <summary>
                /// 
                /// </summary>
                PUT,
                /// <summary>
                /// 
                /// </summary>
                DELETE,
                /// <summary>
                /// 
                /// </summary>
                GET,
                /// <summary>
                /// 
                /// </summary>
                OPTIONS,
                /// <summary>
                /// 
                /// </summary>
                PATCH
            }
            

            """;

        context.AddSource($"DynamicMinimalApiOptions", SourceText.From(apiClass2, Encoding.UTF8));

    }
}
